<?php
class CF_App_Controller_Response_Header
{
	/**
	 * @var array
	 */
	protected $_statusCodes = array(
		100 => 'Continue',
		101 => 'Switching Protocols',
		200 => 'OK',
		201 => 'Created',
		202 => 'Accepted',
		203 => 'Non-Authoritative Information',
		204 => 'No Content',
		205 => 'Reset Content',
		206 => '206 Partial Content',
		300 => 'Multiple Choices',
		301 => 'Moved Permanently',
		302 => 'Found',
		303 => 'See Other',
		304 => 'Not Modified',
		305 => 'Use Proxy',
		307 => 'Temporary Redirect',
		400 => 'Bad Request',
		401 => 'Unauthorized',
		402 => 'Payment Required',
		403 => 'Forbidden',
		404 => 'Not Found 222',
		405 => 'Method Not Allowed',
		406 => 'Not Acceptable',
		407 => 'Proxy Authentication Required',
		408 => 'Request Timeout',
		409 => 'Conflict',
		410 => 'Gone',
		411 => 'Length Required',
		412 => 'Precondition Failed',
		413 => 'Request Entity Too Large',
		414 => 'Request-URI Too Long',
		415 => 'Unsupported Media Type',
		416 => 'Requested Range Not Satisfiable',
		417 => 'Expectation Failed',
		500 => 'Internal Server Error',
		501 => 'Not Implemented',
		502 => 'Bad Gateway',
		503 => 'Service Unavailable',
		504 => 'Gateway Timeout',
		505 => 'HTTP Version Not Supported'
	);
	
	/**
	 * @var array
	 */
	protected $_headersName = array(
		'AcceptRanges' 			=> 'Accept-Ranges',
		'Age' 					=> 'Age',
		'Allow' 				=> 'Allow',
		'CacheControl' 			=> 'Cache-Control',
		'ContentEncoding' 		=> 'Content-Encoding',
		'ContentLanguage' 		=> 'Content-Language',
		'ContentLength' 		=> 'Content-Length',
		'ContentLocation' 		=> 'Content-Location',
		'ContentDisposition' 	=> 'Content-Disposition',
		'ContentMD5' 			=> 'Content-MD5',
		'ContentRange' 			=> 'Content-Range',
		'ContentType' 			=> 'Content-Type',
		'Date' 					=> 'Date',
		'ETag' 					=> 'ETag',
		'Expires' 				=> 'Expires',
		'LastModified' 			=> 'Last-Modified',
		'Location' 				=> 'Location',
		'Pragma' 				=> 'Pragma',
		'ProxyAuthenticate' 	=> 'Proxy-Authenticate',
		'Refresh' 				=> 'Refresh',
		'RetryAfter' 			=> 'Retry-After',
		'Server' 				=> 'Server',
		'SetCookie' 			=> 'Set-Cookie',
		'Trailer' 				=> 'Trailer',
		'Transfer-Encoding' 	=> 'Transfer-Encoding',
		'Vary' 					=> 'Vary',
		'Via' 					=> 'Via',
		'Warning' 				=> 'Warning',
		'WWWAuthenticate' 		=> 'WWW-Authenticate'
	);
	
	/**
	 * @var array
	 */
	protected $_headers = array();
	
	/**
	 * 
	 * @var int
	 */
	protected $_code = null;
	
	/**
	 * @return void
	 */
	public function __construct()
	{
		
	}
	
	/**
	 * 
	 * @param string $name
	 * @return boolean
	 */
	public function has($name)
	{
		return isset($this->_headers[$name]) && !empty($this->_headers[$name]);	
	}
	
	/**
	 * 
	 * @param string $name
	 * @return array
	 */
	public function get($name)
	{
		return $this->has($name)? $this->_headers[$name] : null;
	}
	
	/**
	 * 
	 * @param string $name
	 * @param string $value
	 * @param boolean $replace
	 * @param int $code [optional]
	 * @return CF_App_Controller_Response_Header $this
	 */
	public function add($name, $value, $replace = true, $code = null)
	{
		$name = (string) $name;
		
		$key = str_replace('-', '', $name);
		if(!isset($this->_headersName[$key])){
			throw new CF_App_Controller_Response_Header_Exception(
				"HTTP response header does not support \"$name\""
			);
		}
		$this->_headers[$key][] = array(
			'value' => (string) $value,
			'replace' => (boolean) $replace
		);
		
		if(null !== $code) $this->setCode($code);
		
		return $this;
	}
	
	/**
	 * 
	 * @param string $url
	 * @return CF_App_Controller_Response_Header $this
	 */
	public function redirect($url)
	{
		return $this->location($url);	
	}
	
	/**
	 * 
	 * @param string $name
	 * @param array $args
	 * @return CF_App_Controller_Response_Header
	 */
	public function __call($name, $args)
	{
		$name = ucfirst($name);
		array_unshift($args, $name);
		return call_user_func_array(array($this, 'add'), $args);
	}
	
	/**
	 * 
	 * @param string $name
	 * @return CF_App_Controller_Response_Header $this
	 */
	public function remove($name)
	{
		$key = (string) $name;
		unset($this->_headers[$key]);
		return $this;	
	}
	
	/**
	 * @return CF_App_Controller_Response_Header $this
	 */
	public function reset()
	{
		$this->_headers = array();
		return $this;
	}
	
	/**
	 * @return int
	 */
	public function getCode()
	{
		return $this->_code;	
	}
	
	/**
	 * 
	 * @param int $code
	 * @return CF_App_Controller_Response_Header $this
	 */
	public function setCode($code)
	{
		$code = (int) $code;
		if(!array_key_exists($code, $this->_statusCodes)){
			throw new CF_App_Controller_Response_Header_Exception(
				"HTTP response does not support code \"$code\""
			);
		}
		
		$this->_code = $code;
		return $this;
	}
	
	/**
	 * @return void
	 * @throws CF_App_Controller_Response_Header_Exception
	 */
	protected function _ensureCanSend()
	{
		if(headers_sent($file, $line)){
			throw new CF_App_Controller_Response_Header_Exception(
				"Cannot send headers. Headers already sent in \"$file\" on line \"$line\""
			);
		}
	}
	
	/**
	 * @return CF_App_Controller_Response_Header $this
	 */
	public function send()
	{
		if(!$this->_code && empty($this->_headers)) return;
		
		if(!empty($this->_headers)){
			foreach ($this->_headers as $key => $headers) {
				$this->_ensureCanSend();
				foreach ($headers as $header) {
					if($this->_code){
						header($this->_headersName[$key] . ':' . $header['value'], $header['replace'], $this->_code);
						return $this;
					}else{
						header($this->_headersName[$key] . ':' . $header['value'], $header['replace']);
					}
				}
			}
			return $this;
		}
		
		if($this->_code){
			$this->_ensureCanSend();
			header('HTTP/1.0 ' . $this->_code . ' ' . $this->_statusCodes[$this->_code]);
		}
		
		return $this;
	}
}